package top.fwpsl.redis;

/**
 * list操作
 *
 * @auther: 风戏fw
 * @date: 2020/11/21
 */
public interface IJedisListClient {

    /**
     * BLPOP 是列表的阻塞式(blocking)弹出原语。
     * 它是 LPOP 命令的阻塞版本，当给定列表内没有任何元素可供弹出的时候，连接将被 BLPOP 命令阻塞，直到等待超时或发现可弹出元素为止。
     * 当给定多个 key 参数时，按参数 key 的先后顺序依次检查各个列表，弹出第一个非空列表的头元素。
     * <p>
     * 时间复杂度: O(1)
     *
     * @param timeout 超时参数; 超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) (单位: 秒)
     * @param keys
     * @return
     */
    String[] blpop(int timeout, String... keys);

    String[] brpop(int timeout, String... keys);

    /**
     * BRPOPLPUSH 是 RPOPLPUSH 的阻塞版本，当给定列表 source 不为空时， BRPOPLPUSH 的表现和 RPOPLPUSH 一样。
     * 当列表 source 为空时， BRPOPLPUSH 命令将阻塞连接，直到等待超时，或有另一个客户端对 source 执行 LPUSH 或 RPUSH 命令为止。
     * 超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。
     * <p>
     * 时间复杂度: O(1)
     *
     * @param source
     * @param destination
     * @param timeout
     * @return
     */
    String[] blpoprpush(String source, String destination, int timeout);

    /**
     * 返回列表 key 中，下标为 index 的元素。
     * 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
     * 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * 如果 key 不是列表类型，返回一个错误。
     * <p>
     * O(N)， N为到达下标 index 过程中经过的元素数量
     *
     * @param key
     * @param index
     * @return 列表中下标为 index 的元素。 如果 index 参数的值不在列表的区间范围内(out of range)，返回 nil
     */
    String lindex(String key, int index);

    /**
     * 将值 value 插入到列表 key 当中，位于值 pivot 之前或之后。
     * 当 pivot 不存在于列表 key 时，不执行任何操作。
     * 当 key 不存在时， key 被视为空列表，不执行任何操作。
     * 如果 key 不是列表类型，返回一个错误。
     * <p>
     * 时间复杂度: O(N), N为寻找 pivot 过程中经过的元素数量
     *
     * @param key
     * @param type  取值 ‘BEFORE|AFTER’
     * @param pivot
     * @param value
     * @return 如果命令执行成功, 返回插入操作完成之后, 列表的长度。 如果没有找到 pivot,返回-1; 如果key不存在或为空列表，返回 0
     */
    int linsert(String key, byte type, Object pivot, Object value);

    /**
     * 返回列表 key 的长度。
     * 如果 key 不存在，则 key 被解释为一个空列表，返回 0 .
     * 如果 key 不是列表类型，返回一个错误。
     * <p>
     * 时间复杂度: O(1)
     *
     * @param key
     * @return 列表 key 的长度
     */
    int llen(String key);

    /**
     * 移除并返回列表 key 的头元素
     * <p>
     * 时间复杂度: O(1)
     *
     * @param key
     * @return 列表的头元素。当 key 不存在时，返回 nil 。
     */
    Object lpop(String key);

    /**
     * 将一个或多个值 value 插入到列表 key 的表头
     * 如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表头
     * 如果 key 不存在，一个空列表会被创建并执行 LPUSH 操作。
     * 当 key 存在但不是列表类型时，返回一个错误
     * <p>
     * 时间复杂度: O(1)
     *
     * @param key
     * @param values
     * @return 执行 LPUSH 命令后，列表的长度
     */
    int lpush(String key, String... values);

    /**
     * 将值 value 插入到列表 key 的表头，当且仅当 key 存在并且是一个列表。
     * 和 LPUSH 命令相反，当 key 不存在时， LPUSHX 命令什么也不做。
     * <p>
     * 时间复杂度: O(1)
     *
     * @param key
     * @param value
     * @return 命令执行之后，表的长度
     */
    int lpushx(String key, String value);

    /**
     * 返回列表key中指定区间内的元素，区间以偏移量start和stop指定。
     * 下标(index)参数start和stop都以 0 为底，也就是说，以0表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
     * 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * <p>
     * 时间复杂度: O(S+N)， S 为偏移量 start ， N 为指定区间内元素的数量
     *
     * @param key
     * @param start
     * @param stop
     * @return 一个列表，包含指定区间内的元素
     */
    String[] lrange(String key, int start, int stop);

    /**
     * 根据参数 count 的值，移除列表中与参数 value 相等的元素
     * <p>
     * count 的值可以是以下几种：
     * 1、 count > 0 : 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。
     * 2、 count < 0 : 从表尾开始向表头搜索，移除与 value 相等的元素，数量为 count 的绝对值。
     * 3、 count = 0 : 移除表中所有与 value 相等的值。
     * <p>
     * 时间复杂度: O(N), N为列表的长度
     *
     * @param key
     * @param count
     * @param value
     * @return 被移除元素的数量; 因为不存在的 key 被视作空表(empty list)，所以当 key 不存在时， LREM 命令总是返回 0
     */
    int lrem(String key, int count, String value);

    /**
     * 将列表key下标为 index 的元素的值设置为 value 。
     * 当 index 参数超出范围，或对一个空列表( key不存在)进行 LSET 时，返回一个错误。
     * <p>
     * 时间复杂度: O(N)， N 为列表的长度
     *
     * @param key
     * @param index
     * @param value
     * @return 操作成功返回 ok ，否则返回错误信息
     */
    boolean lset(String key, int index, String value);

    /**
     * 对一个列表进行修剪(trim)，就是说，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除。
     * 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。
     * 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * 当 key 不是列表类型时，返回一个错误。
     * <p>
     * 时间复杂度: O(N)， N 为被移除的元素的数量
     *
     * @param key
     * @param start
     * @param stop
     * @return 命令执行成功时，返回 ok
     */
    boolean ltrim(String key, int start, int stop);

    /**
     * 移除并返回列表 key 的尾元素
     * <p>
     * 时间复杂度: O(1)
     *
     * @param key
     * @return 列表的尾元素; 当 key 不存在时，返回 nil
     */
    String rpop(String key);

    /**
     * 命令 RPOPLPUSH 在一个原子时间内，执行以下两个动作：
     * > 将列表 source 中的最后一个元素(尾元素)弹出，并返回给客户端。
     * > 将 source 弹出的元素插入到列表 destination ，作为 destination 列表的的头元素。
     * <p>
     * 如果source不存在，值nil被返回，并且不执行其他动作。
     * 如果source和destination相同，则列表中的表尾元素被移动到表头，并返回该元素，可以把这种特殊情况视作列表的旋转(rotation)操作。
     * <p>
     * 时间复杂度: O(1)
     *
     * @param source
     * @param destination
     * @return 被弹出的元素
     */
    String rpoplpush(String source, String destination);

    /**
     * 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
     * 如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表尾
     * 如果 key 不存在，一个空列表会被创建并执行 RPUSH 操作。
     * 当 key 存在但不是列表类型时，返回一个错误。
     * <p>
     * 时间复杂度: O(1)
     *
     * @param key
     * @param values
     * @return 执行 RPUSH 操作后，表的长度
     */
    int rpush(String key, String... values);

    /**
     * 将值 value 插入到列表 key 的表尾，当且仅当 key 存在并且是一个列表。
     * 和 RPUSH 命令相反，当 key 不存在时， RPUSHX 命令什么也不做。
     *
     * 时间复杂度: O(1)
     *
     * @param key
     * @param value
     * @return
     */
    int rpushx(String key, String value);

}
